package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.cloudfun.campusshare.common.constant.ProductType;
import com.cloudfun.campusshare.common.constant.ReportFormTimeFilter;
import com.cloudfun.campusshare.common.model.vo.*;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.entity.UserEntity;
import com.cloudfun.campusshare.repo.DeviceEntityRepo;
import com.cloudfun.campusshare.repo.sql.SqlUtils;
import com.cloudfun.campusshare.service.ReportFormService;
import com.cloudfun.campusshare.service.UserPreferWashPointService;
import com.cloudfun.campusshare.service.UserRelService;
import com.cloudfun.campusshare.util.AmountUtil;
import com.cloudfun.campusshare.util.DateUtil;
import com.cloudfun.campusshare.util.QueryUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static com.cloudfun.campusshare.common.constant.ReportFormTimeFilter.getByCode;

/**
 * @author : zhangyongjie
 * @version : 1.0
 * @createTime : 2020/5/12 14:52
 * @description :
 */
@Service
public class ReportFormServiceImpl implements ReportFormService {

    @Resource
    private DeviceEntityRepo deviceEntityRepo;

    @Resource
    private EntityManager entityManager;

    @Autowired
    private UserPreferWashPointService userPreferWashPointService;
    @Autowired
    private UserRelService userRelService;

    @Override
    public MerchantReportVO queryMerchantReportForm(Integer timeCon, List<String> deviceType) {
        MerchantReportVO merchantReportVO = new MerchantReportVO();
        merchantReportVO.setDeviceCount(getDeviceCount());
        merchantReportVO.setMerchantCount(getMerchantCount());
        switch (getByCode(timeCon)) {
            case SELF_MONTH:
                merchantReportVO.setIncreDeviceCount(getPerMonthReport(deviceType, true));
                merchantReportVO.setIncreMerchantCount(getPerMonthReport(null, false));
                break;
            case HALF_YEAR:
                merchantReportVO.setIncreDeviceCount(getHalfReport(deviceType, true));
                merchantReportVO.setIncreMerchantCount(getHalfReport(null, false));
                break;
            case TOTAL_YEAR:
                merchantReportVO.setIncreDeviceCount(getTotalReport(deviceType, true));
                merchantReportVO.setIncreMerchantCount(getTotalReport(null, false));
                break;

        }
        return merchantReportVO;
    }

    @Override
    public OrderReportVO queryOrderReportForm(String merchantId, Integer timeCon, List<String> deviceType) {
        OrderReportVO orderReportVO = new OrderReportVO();
        switch (getByCode(timeCon)) {
            case TODAY:
                getCurrentDayData(merchantId, deviceType, orderReportVO, null, ReportFormTimeFilter.TODAY);
                break;
            case YESTER_DAY:
                getCurrentDayData(merchantId, deviceType, orderReportVO, null, ReportFormTimeFilter.YESTER_DAY);
                break;
            case IN_SEVEN_DAY:
                getLastDay(merchantId, deviceType, orderReportVO, 6, null);
                break;
            case IN_MONTH:
                int days = new Long(ChronoUnit.DAYS.between(LocalDate.now().minusMonths(1), LocalDate.now())).intValue();
                getLastDay(merchantId, deviceType, orderReportVO, days, null);
                break;
            case THREE_MONTH:
                getLastDay(merchantId, deviceType, orderReportVO, new Long(ChronoUnit.DAYS.between(LocalDate.now().minusMonths(3), LocalDate.now())).intValue(), null);
                break;
            case SIX_MONTH:
                getLastDay(merchantId, deviceType, orderReportVO, new Long(ChronoUnit.DAYS.between(LocalDate.now().minusMonths(6), LocalDate.now())).intValue(), null);
                break;
            case TWELVE_MONTH:
                getLastDay(merchantId, deviceType, orderReportVO, new Long(ChronoUnit.DAYS.between(LocalDate.now().minusMonths(12), LocalDate.now())).intValue(), null);
                break;
        }
        return orderReportVO;
    }

    @Override
    public OrderReportVO omQueryOrderReport(Integer timeCon, String preferWashPointId) {
        String merchantId = AuthenticationHolder.getUserId();
        OrderReportVO orderReportVO = new OrderReportVO();
        switch (getByCode(timeCon)) {
            case TODAY:
                getCurrentDayData(merchantId, new ArrayList<>(), orderReportVO, preferWashPointId, ReportFormTimeFilter.TODAY);
                break;
            case IN_SEVEN_DAY:
                getLastDay(merchantId, new ArrayList<>(), orderReportVO, 6, preferWashPointId);
                break;
            case IN_MONTH:
                int days = new Long(ChronoUnit.DAYS.between(LocalDate.now().minusMonths(1), LocalDate.now())).intValue();
                getLastDay(merchantId, new ArrayList<>(), orderReportVO, days, preferWashPointId);
                break;
        }
        return orderReportVO;
    }

    @Override
    public List<MerchantReportFormExportListVO> exportMerchantReportForm(Integer timeCon, List<String> deviceType) {
        MerchantReportVO merchantReportVO = queryMerchantReportForm(timeCon, deviceType);
        Map<String, Long> increDeviceCount = merchantReportVO.getIncreDeviceCount();
        Map<String, Long> increMerchantCount = merchantReportVO.getIncreMerchantCount();

        String combineType = CollectionUtil.isEmpty(deviceType) ? "全部" : deviceType.stream().reduce(new StringJoiner(","), StringJoiner::add, StringJoiner::merge).toString();


        List<MerchantReportFormExportListVO> collect = increDeviceCount.entrySet().stream().map(x -> {
            MerchantReportFormExportListVO merchantReportFormExportListVO = new MerchantReportFormExportListVO();
            merchantReportFormExportListVO.setTime(x.getKey());
            merchantReportFormExportListVO.setDeviceKind(combineType);
            merchantReportFormExportListVO.setDeviceCount(x.getValue());
            merchantReportFormExportListVO.setMerchantCount(increMerchantCount.get(x.getKey()));
            return merchantReportFormExportListVO;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public List<ConsumeReportExportVO> exportConsumeReportForm(String merchantId, Integer timeCon, List<String> deviceType) {
        OrderReportVO orderReportVO = queryOrderReportForm(merchantId, timeCon, deviceType);
        Map<String, String> moneyAmount = orderReportVO.getMoneyAmount();
        Map<String, Long> orderCount = orderReportVO.getOrderCount();
        String combineType = CollectionUtil.isEmpty(deviceType) ? "全部" : ProductType.valueOf(deviceType.stream().reduce(new StringJoiner(","), StringJoiner::add, StringJoiner::merge).toString()).getDesc();
        List<ConsumeReportExportVO> collect = moneyAmount.entrySet().stream().map(x -> {
            ConsumeReportExportVO consumeReportExportVO = new ConsumeReportExportVO();
            consumeReportExportVO.setTime(x.getKey());
            consumeReportExportVO.setOrderAmount(x.getValue());
            consumeReportExportVO.setDeviceType(combineType);
            consumeReportExportVO.setOrderCount(orderCount.get(x.getKey()));
            //先写死
            consumeReportExportVO.setRefundAmount("0.00");
            consumeReportExportVO.setRefundCount(0L);
            consumeReportExportVO.setActualGain(x.getValue());
            return consumeReportExportVO;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public OperatorProfileVo operatorProfile(String merchantId) {
        String sql = "SELECT COALESCE(SUM( price ),0)  FROM device_order WHERE from_unixtime( create_time/1000 ,'%Y-%m-%d') BETWEEN (SELECT DATE_FORMAT(DATE_SUB( curdate( ), INTERVAL {} DAY ), '%Y-%m-%d')) AND (SELECT DATE_FORMAT(DATE_SUB( curdate( ), INTERVAL {} DAY ), '%Y-%m-%d'))";
        OperatorProfileVo vo = new OperatorProfileVo();
        vo.setTodayTotalIncome(AmountUtil.amountRoundStr(operatorProfile(sql, merchantId, 0, 0), 2));
        vo.setYesterdayTotalIncome(AmountUtil.amountRoundStr(operatorProfile(sql, merchantId, 1, 1), 2));
        vo.setSelfWeekTotalIncome(AmountUtil.amountRoundStr(operatorProfile(sql, merchantId, 6, 0), 2));
        vo.setSelfMonthTotalIncome(AmountUtil.amountRoundStr(operatorProfile(sql, merchantId, 30, 0), 2));
        return vo;
    }

    public BigDecimal operatorProfile(String sql, String merchantId, Integer startTime, Integer endTime) {
        StringBuilder builder = new StringBuilder(StrUtil.format(sql, startTime, endTime));
        if (AuthenticationHolder.isAdmin()) {
            if (StringUtils.isNotBlank(merchantId)) {
                builder.append(" and user_id=:merchantId ");
            }
        } else {
            String userId = AuthenticationHolder.getUserId();
            UserEntity userMerchant = userRelService.getUserMerchant(userId);
            builder.append(" and user_id='").append(userMerchant.getId()).append("'");
        }
        Query nativeQuery = entityManager.createNativeQuery(builder.toString());
        if (AuthenticationHolder.isAdmin()) {
            if (StringUtils.isNotBlank(merchantId)) {
                nativeQuery.setParameter("merchantId", merchantId);
            }
        }
        return (BigDecimal) nativeQuery.getSingleResult();
    }


    private void getCurrentDayData(String merchantId, List<String> deviceType, OrderReportVO orderReportVO, String preferWashPointId, ReportFormTimeFilter reportFormTimeFilter) {
        String sql = "select a.time,count(od.id) as orderNum,SUM(priceA) as totalPrice from( {} ) a LEFT JOIN ( SELECT DISTINCT o.id as id,{},o.create_time FROM device_order o LEFT JOIN device d ON o.device_id = d.id LEFT JOIN liquid_pump_order pump_order ON pump_order.order_id=o.id WHERE 1 = 1  and o.order_status='ALREADY_COMPLETE'";
        if (reportFormTimeFilter.equals(ReportFormTimeFilter.YESTER_DAY)) {
            sql = StrUtil.format(sql, SqlUtils.YESTER_DAY_24_LIST);
        } else {
            sql = StrUtil.format(sql, SqlUtils.TO_DAY_24_LIST);
        }
        if (CollectionUtil.isNotEmpty(deviceType)) {
            if (deviceType.contains(ProductType.WASHING_MACHINE.name())) {
                sql = StrUtil.format(sql, "o.price-(COALESCE(pump_order.first_pump_price,0)+COALESCE(pump_order.second_pump_price,0)) AS priceA");
            } else if (deviceType.contains(ProductType.LIQUID_PUMP.name())) {
                sql = StrUtil.format(sql, "(COALESCE(pump_order.first_pump_price,0)+COALESCE(pump_order.second_pump_price,0)) AS priceA");
            } else {
                sql = StrUtil.format(sql, "o.price AS priceA");
            }
        } else {
            sql = StrUtil.format(sql, "o.price AS priceA");
        }
        StringBuilder sb = new StringBuilder(sql);
        if (AuthenticationHolder.isAdmin()) {
            if (StringUtils.isNotBlank(merchantId)) {
                sb.append(" and o.user_id=:merchantId ");
            }
        } else {
            String userId = AuthenticationHolder.getUserId();
            UserEntity userMerchant = userRelService.getUserMerchant(userId);
            sb.append(" and o.user_id='").append(userMerchant.getId()).append("'");
        }

        if (CollectionUtil.isNotEmpty(deviceType)) {
            sb.append(" and d.product_type in :deviceType");
            if (deviceType.contains(ProductType.LIQUID_PUMP.name())) {
                sb.append(" and o.command is not null");
            }
        }
        if (StringUtils.isNotBlank(preferWashPointId)) {
            sb.append(" and d.wash_point_id=:washPointId");
        }
        sb.append(" ) od on from_unixtime( CAST( od.create_time AS SIGNED )/ 1000 ,'%Y-%m-%d %H')= a.time GROUP BY a.time");
        Query nativeQuery = entityManager.createNativeQuery(sb.toString());
        if (AuthenticationHolder.isAdmin()) {
            if (StringUtils.isNotBlank(merchantId)) {
                nativeQuery.setParameter("merchantId", merchantId);
            }
        }
        if (CollectionUtil.isNotEmpty(deviceType)) {
            if (deviceType.contains(ProductType.LIQUID_PUMP.name())) {
                nativeQuery.setParameter("deviceType", Arrays.asList(ProductType.WASHING_MACHINE.name()));
            }else {
                nativeQuery.setParameter("deviceType", deviceType);
            }
        }
        if (StringUtils.isNotBlank(preferWashPointId)) {
            nativeQuery.setParameter("washPointId", preferWashPointId);
        }
        List<Object[]> resultList = nativeQuery.getResultList();
        Map<String, String> price = new TreeMap<>();
        Map<String, Long> count = new TreeMap<>();
        resultList.stream().forEach(x -> {
            String time = (String) x[0];
            Long orderCount = Optional.ofNullable(x[1]).map(x1 -> ((BigInteger) x1).longValue()).orElse(0L);
            Integer totalPrice = Optional.ofNullable(x[2]).map(x1 -> ((BigDecimal) x1).intValue()).orElse(0);
            price.put(time, AmountUtil.amountRoundStr(totalPrice, 2));
            count.put(time, orderCount);
        });
        orderReportVO.setMoneyAmount(price);
        orderReportVO.setOrderCount(count);
    }

    private void getLastDay(String merchantId, List<String> deviceType, OrderReportVO orderReportVO, int lastDay, String preferWashPointId) {
        StringBuilder sb = new StringBuilder("SELECT a.date, count(od.id) as orderNum, SUM(priceA) as totalPrice" +
                " FROM ( SELECT @s \\:=@s + 1 AS `index`, DATE(DATE_SUB(CURRENT_DATE, INTERVAL @s DAY)) AS `date` " +
                " FROM mysql.help_topic,(SELECT @s \\:= -1) temp WHERE @s <  " + lastDay + " ORDER BY `date` ) a " +
                " LEFT JOIN ( SELECT DISTINCT o.id as id,"
        );
        if (CollectionUtil.isNotEmpty(deviceType)) {
            if (deviceType.contains(ProductType.WASHING_MACHINE.name())) {
                sb.append("o.price-(COALESCE(pump_order.first_pump_price,0)+COALESCE(pump_order.second_pump_price,0)) AS priceA");
            } else if (deviceType.contains(ProductType.LIQUID_PUMP.name())) {
                sb.append("(COALESCE(pump_order.first_pump_price,0)+COALESCE(pump_order.second_pump_price,0)) AS priceA");
            } else {
                sb.append("o.price AS priceA");
            }
        } else {
            sb.append("o.price AS priceA");
        }
        sb.append(",o.create_time FROM device_order o LEFT JOIN device d ON o.device_id = d.id " +
                " LEFT JOIN liquid_pump_order pump_order ON pump_order.order_id=o.id" +
                " where 1=1 and o.order_status='ALREADY_COMPLETE'");
        if (AuthenticationHolder.isAdmin()) {
            if (StringUtils.isNotBlank(merchantId)) {
                sb.append(" and o.user_id=:merchantId ");
            }
        } else {
            String userId = AuthenticationHolder.getUserId();
            UserEntity userMerchant = userRelService.getUserMerchant(userId);
            sb.append(" and o.user_id='").append(userMerchant.getId()).append("'");
        }
        if (CollectionUtil.isNotEmpty(deviceType)) {
            sb.append(" and d.product_type in :deviceType");
            if (deviceType.contains(ProductType.LIQUID_PUMP.name())) {
                sb.append(" and o.command is not null");
            }
        }
        if (StringUtils.isNotBlank(preferWashPointId)) {
            sb.append(" and d.wash_point_id=:washPointId");
        }
        sb.append(" )od on DATE( from_unixtime( CAST( od.create_time AS SIGNED )/ 1000 ))= a.date GROUP BY a.date");

        Query nativeQuery = entityManager.createNativeQuery(sb.toString());
        if (AuthenticationHolder.isAdmin()) {
            if (StringUtils.isNotBlank(merchantId)) {
                nativeQuery.setParameter("merchantId", merchantId);
            }
        }
        if (CollectionUtil.isNotEmpty(deviceType)) {
            if (deviceType.contains(ProductType.LIQUID_PUMP.name())) {
                nativeQuery.setParameter("deviceType", Arrays.asList(ProductType.WASHING_MACHINE.name()));
            }else {
                nativeQuery.setParameter("deviceType", deviceType);
            }
        }
        if (StringUtils.isNotBlank(preferWashPointId)) {
            nativeQuery.setParameter("washPointId", preferWashPointId);
        }
        List<Object[]> resultList = nativeQuery.getResultList();
        Map<String, String> price = new TreeMap<>();
        Map<String, Long> count = new TreeMap<>();
        resultList.forEach(x -> {
            String date = DateUtil.dateToString((Date) x[0], "yyyy-MM-dd");
            Long orderCount = Optional.ofNullable(x[1]).map(x1 -> ((BigInteger) x1).longValue()).orElse(0L);
            Integer totalPrice = Optional.ofNullable(x[2]).map(x1 -> ((BigDecimal) x1).intValue()).orElse(0);
            price.put(date, AmountUtil.amountRoundStr(totalPrice, 2));
            count.put(date, orderCount);
        });
        orderReportVO.setMoneyAmount(price);
        orderReportVO.setOrderCount(count);
    }

    private Long getDeviceCount() {
        return deviceEntityRepo.count();
    }

    private Long getMerchantCount() {
        StringBuilder sb = new StringBuilder("select count(*) from user u left join user_role ur on u.id = ur.user_id left join role r on ur.role_id = r.id where r.type='OPERATIONAL_MERCHANT'");
        Query query = entityManager.createNativeQuery(sb.toString());
        Long count = Optional.ofNullable(((BigInteger) QueryUtil.getSingleResult(query)).longValue()).orElse(0L);
        return count;
    }

    private Map<String, Long> getPerMonthReport(List<String> deviceType, Boolean isDevice) {
        StringBuilder sb;
        if (isDevice) {
            sb = new StringBuilder("select da.date,count(d.id) as count from (SELECT @a \\:=@a + 1 as `index`, DATE(ADDDATE(CURRENT_DATE, INTERVAL @a DAY)) AS `date`" +
                    " FROM mysql.help_topic,(SELECT @a \\:= 0) temp WHERE @a < DAY(LAST_DAY(CURRENT_DATE)) - DAY(CURRENT_DATE) UNION SELECT @s \\:=@s - 1 as `index`," +
                    " DATE(DATE_SUB(CURRENT_DATE, INTERVAL @s DAY)) AS `date` FROM mysql.help_topic,(SELECT @s \\:= day(CURRENT_DATE)) temp WHERE @s > 0 ORDER BY `date`) da left join (select * from device");
            if (CollectionUtil.isNotEmpty(deviceType)) {
                sb.append(" where product_type in :deviceType");
            }

            sb.append(") d on da.date = DATE(from_unixtime(CAST(d.create_time AS SIGNED)/1000)) GROUP BY da.date");
        } else {
            sb = new StringBuilder("select da.date,count(u.id) as count from (SELECT @a \\:=@a + 1 as `index`, DATE(ADDDATE(CURRENT_DATE, INTERVAL @a DAY)) AS `date` " +
                    "FROM mysql.help_topic,(SELECT @a \\:= 0) temp WHERE @a < DAY(LAST_DAY(CURRENT_DATE)) - DAY(CURRENT_DATE) UNION" +
                    " SELECT @s \\:=@s - 1 as `index`, DATE(DATE_SUB(CURRENT_DATE, INTERVAL @s DAY)) AS `date` FROM mysql.help_topic,(SELECT @s \\:= day(CURRENT_DATE)) temp" +
                    " WHERE @s > 0 ORDER BY `date`) da left join (select u.id,u.create_time from user u left join user_role ur on u.id = ur.user_id left join" +
                    " role r on ur.role_id = r.id where r.type='OPERATIONAL_MERCHANT') u on da.date = DATE(from_unixtime(CAST(u.create_time AS SIGNED)/1000)) GROUP BY da.date");
        }

        Query query = entityManager.createNativeQuery(sb.toString());
        if (CollectionUtil.isNotEmpty(deviceType)) {
            query.setParameter("deviceType", deviceType);
        }

        Map<String, Long> map = new TreeMap<>();
        List<Object[]> resultList = query.getResultList();
        resultList.stream().forEach(x -> {
            String date = DateUtil.dateToString((Date) x[0], "yyyy-MM-dd");
            Long count = Optional.ofNullable(x[1]).map(x1 -> ((BigInteger) x1).longValue()).orElse(0L);
            map.put(date, count);
        });
        return map;
    }


    private Map<String, Long> getHalfReport(List<String> deviceType, Boolean isDevice) {
        StringBuilder sb;
        if (isDevice) {
            sb = new StringBuilder("select a.lastDays,count(d.id) as count from (SELECT date_format(@lastDay \\:= last_day( date_add(@lastDay,interval 1 month ) ) ,'%Y-%m'  ) lastDays " +
                    "from (SELECT @lastDay \\:= date_add(curdate(),interval -6 month) from application  limit 6) a) a left join (select * from device");
            if (CollectionUtil.isNotEmpty(deviceType)) {
                sb.append(" where product_type in :deviceType");
            }

            sb.append(") d on a.lastDays = from_unixtime(CAST(d.create_time AS SIGNED)/1000,'%Y-%m')  GROUP BY a.lastDays ");
        } else {
            sb = new StringBuilder("select a.lastDays,count(u.id) as count from (SELECT date_format(@lastDay \\:= last_day( date_add(@lastDay,interval 1 month ) ) ,'%Y-%m'  ) lastDays " +
                    "from (SELECT @lastDay \\:= date_add(curdate(),interval -6 month) from application  limit 6) a)a left join" +
                    " (select u.id,u.create_time from user u left join user_role ur on u.id = ur.user_id left join role r on ur.role_id = r.id" +
                    " where r.type='OPERATIONAL_MERCHANT') u on a.lastDays = from_unixtime(CAST(u.create_time AS SIGNED)/1000,'%Y-%m')  GROUP BY a.lastDays ");
        }

        Query query = entityManager.createNativeQuery(sb.toString());
        if (CollectionUtil.isNotEmpty(deviceType)) {
            query.setParameter("deviceType", deviceType);
        }
        Map<String, Long> map = new TreeMap<>();
        List<Object[]> resultList = query.getResultList();
        resultList.stream().forEach(x -> {
            String date = (String) x[0];
            Long count = Optional.ofNullable(x[1]).map(x1 -> ((BigInteger) x1).longValue()).orElse(0L);
            map.put(date, count);
        });
        return map;
    }

    private Map<String, Long> getTotalReport(List<String> deviceType, Boolean isDevice) {
        StringBuilder sb;
        if (isDevice) {
            sb = new StringBuilder("select a.lastDays,count(d.id) as count from (SELECT date_format(@lastDay \\:= last_day( date_add(@lastDay,interval 1 month ) ) ,'%Y-%m'  ) lastDays " +
                    "from (SELECT @lastDay \\:= date_add(curdate(),interval -12 month) from application  limit 12) a) a left join (select * from device");
            if (CollectionUtil.isNotEmpty(deviceType)) {
                sb.append(" where product_type in :deviceType");
            }

            sb.append(") d on a.lastDays = from_unixtime(CAST(d.create_time AS SIGNED)/1000,'%Y-%m')  GROUP BY a.lastDays ");
        } else {
            sb = new StringBuilder("select a.lastDays,count(u.id) as count from (SELECT date_format(@lastDay \\:= last_day( date_add(@lastDay,interval 1 month ) ) ,'%Y-%m'  ) lastDays " +
                    "from (SELECT @lastDay \\:= date_add(curdate(),interval -12 month) from application  limit 12) a) a left join (select u.id,u.create_time from user u left join" +
                    " user_role ur on u.id = ur.user_id left join role r on ur.role_id = r.id where r.type='OPERATIONAL_MERCHANT') u on a.lastDays = from_unixtime(CAST(u.create_time AS SIGNED)/1000,'%Y-%m')" +
                    " GROUP BY a.lastDays ");

        }
        Query query = entityManager.createNativeQuery(sb.toString());
        if (CollectionUtil.isNotEmpty(deviceType)) {
            query.setParameter("deviceType", deviceType);
        }
        Map<String, Long> map = new TreeMap<>();
        List<Object[]> resultList = query.getResultList();
        resultList.stream().forEach(x -> {
            String date = (String) x[0];
            Long count = Optional.ofNullable(x[1]).map(x1 -> ((BigInteger) x1).longValue()).orElse(0L);
            map.put(date, count);
        });
        return map;
    }

}
